JRockit中的另一种Management API就是JMXMAPI,它可看作是给予JMX的JMAPI,两者虽然不是一一对应,但总体上差不多。目前,JMXMAPI还不是官方支持的,可能会在将来的版本中有较大变动。
在JRockit的每个发行版中,JMXMAPI中MBean的域名都会发生变化。在R28版本中,由于Oracle收购BEA,它又变了。 估计最近一段时间Oracle不太可能被收购,所以期望这次域名能保持较长一段时间。起初,JMXMAPI的MBean是与java.lang.management
域中的MBean(参见第7章的内容)放在一起的,后来把它放到了bea.jrockit.management
域下,最后有把它已到了oracle.jrockit.management
域下。若想以版本无关的方式访问JMX,可以使用第7章中介绍的 RJMX代理层来实现。
若想访问JMXMAPI,就必须要先载入JRockitConsoleMBean
,具体来说,可以通过MBeanServerConnection
来编程实现。
在R27.x版本中,可以是这样:
someMBeanServerConnection.createMBean("bea.jrockit.management.JRockitConsole", null);
在R28.x版本中,则是这样:
someMBeanServerConnection.createMBean("oracle.jrockit.management.JRockitConsole", null);
有了Management Console的代理层,这一切就可以自动完成了。
各个MBean是按照功能来分组的。在R28版本中,还可以自动创建JFR所需要的MBean。
在下面的表格中,介绍了可用的MBean:
JMXMAPI MBeans
MBean name Description
Compilation 有关JIT编译器的信息
DiagnosticCommand 访问JVM内部诊断命令,参见第11章相关内容
GarbageCollector 有关垃圾回收器的相关信息,可以对垃圾回收器进行调整
JRockitConsole Management Console的相关功能,例如转储堆。创建该MBean时会实例化并注册相关的API
Log 控制JRockit日志模块
Memleak 控制Memleak服务器
Memory 访问物理内存
PerfCounters 这是一个动态生成的MB额按,可以列出所有的内部性能计数器
Profiler 控制方法分析器
Runtime 可以获取CPU信息,CPU负载,以及控制CPU亲和性
Threading 获取县城相关信息。目前只包含操作,还没有属性可用
在R28版本中,还可以通过基于JMX的API来启动/控制JFR。该MBean在com.oracle.jrockit
域下,起入口点在MBeanFlightRecorder
中。它并不属于JMXMAPI。
大部分JMXMAPI都是通过MBean实现暴露出来的,而PerfCountersMBean
则是动态生成的。JRockit在内部会使用一系列性能计数器来完成分析和诊断操作。每个JRockit内部性能计数器都对应了PerfCountersMBean
中的一个属性。
由于JMXMAPI不受支持,因此连带着动态生成的
PerfCountersMBean
也得不到支持。不过,它们之间还是有区别的,jrockit.*
包下的计数器比oracle.*
包下的计数器更不受待见,支持更少。
下表介绍了在4.0/R28.x版本(在写书时,共有139种计数器)中最重要的几种计数器:
Counter Description
java.cls.loadedClasses 启动JVM之后,共载入了多少类
java.cls.unloadedClasses 启动JVM之后,共卸载了多少类
java.property.java.class.path JVM的CLASSPATH路径
java.property.java.endorsed.dirs 有关`endorsed`目录的说明,请参见http://docs.oracle.com/javase/6/docs/中, **Endorsed Standards Override Mechanism**节的说明
java.property.java.ext.dirs 扩展目录中的jar包会被自动添加到CLASSPATH中,参见JavaDoc中队`java.ext.dirs`的说明。更多详细内容,请参见http://java.sun.com/j2se/1.4.2/docs/guide/extensions/spec.html
java.property.java.home JDK或JRE的安装路径
java.property.java.library.path 用户库的路径
java.property.java.vm.version JRockit版本号
java.rt.vmArgs JVM参数
java.threads.daemon 守护线程数目
java.threads.live 运行中的线程的数目
java.threads.livePeak JVM启动后,同时运行的线程数目的峰值
java.threads.nonDaemon 运行中的、非守护线程的数目
java.threads.started JRockit启动后,开启的线程的总数目
jrockit.gc.latest.heapSize 当前堆大小,单位为字节
jrockit.gc.latest.nurserySize 当前年轻代大小,单位为字节
jrockit.gc.latest.oc.compaction.time 上一次执行内存整理所花费的时间,单位为系统滴答数(ticks),如果想跳过内存整理操作,可将之置为0
jrockit.gc.latest.oc.heapUsedAfter 上一次老年代垃圾回收结束之后,堆中已使用的内存总量,单位为字节
jrockit.gc.latest.oc.heapUsedBefore 上一次老年代垃圾回收开始之前,堆中已使用的内存总量,单位为字节
jrockit.gc.latest.oc.number 到目前为止,所执行过的老年代垃圾回收的次数
jrockit.gc.latest.oc.sumOfPauses 上一次老年代垃圾回收中应用程序的暂停时间,单位为系统滴答数(ticks)
jrockit.gc.latest.oc.time 上一次老年代垃圾回收的持续时间,单位为系统滴答数(ticks)
jrockit.gc.latest.yc.sumOfPauses 上一次年轻代垃圾回收中应用程序的暂停时间,单位为系统滴答数(ticks)
jrockit.gc.latest.yc.time 上一次年轻代垃圾回收的持续时间,单位为系统滴答数(ticks)
jrockit.gc.max.oc.individualPause 到目前为止,持续时间最长的老年代垃圾回收的持续时间,单位为系统滴答数(ticks)
jrockit.gc.max.yc.individualPause 到目前为止,持续时间最长的年轻代垃圾回收的持续时间,单位为系统滴答数(ticks)
jrockit.gc.total.oc.compaction.externalAborted 到目前为止,被终止的外部整理的次数
jrockit.gc.total.oc.compaction.internalAborted 到目前为止,被终止的内部整理的次数
jrockit.gc.total.oc.compaction.internalSkipped 到目前为止,被跳过的内部整理的次数
jrockit.gc.total.oc.compaction.time 到目前为止,执行内存整理所花费的总时间,单位为系统滴答数(ticks)
jrockit.gc.total.oc.ompaction.externalSkipped 到目前为止,被跳过的内部整理的次数
jrockit.gc.total.oc.pauseTime 到目前为止,所有老年代垃圾回收导致应用程序暂停的总时间,单位为系统滴答数(ticks)
jrockit.gc.total.oc.time 到目前为止,花费在老年代垃圾回收的总时间,单位为系统滴答数(ticks)
jrockit.gc.total.pageFaults 到目前为止,在垃圾回收过程中所遇到的页错误(page fault)的总数目
jrockit.gc.total.yc.pauseTime 到目前为止,所有年轻代垃圾回收导致应用程序暂停的总时间,单位为系统滴答数(ticks)
jrockit.gc.total.yc.promotedObjects 到目前为止,从年轻代提升到老年代的对象的总数目
jrockit.gc.total.yc.promotedSize 到目前为止,从年轻代提升到老年代的对象的总字节数
jrockit.gc.total.yc.time 到目前为止,花费在年轻代垃圾回收的总时间,单位为系统滴答数(ticks)
oracle.ci.jit.count 到目前为止,经过JIT编译的方法总数
oracle.ci.jit.timeTotal 到目前为止,花费在JIT编译上的总时间,单位为系统滴答数(ticks)
oracle.ci.opt.count 到目前为止,有多少方法被优化过
oracle.ci.opt.timeTotal 到目前为止,花费在优化上的总时间,单位为系统滴答数(ticks)
oracle.rt.counterFrequency 用于将系统滴答数转换为以秒为单位的时间
这些计时器都非常有用,需要注意的是,不少计时器是以系统滴答数为单位的,使用时,需要先将之转换为以秒为单位(将滴答数除以计数器oracle.rt.counterFrequency
的值即可)。
在 MBean Browser中,编辑表设置,显示出 Description字段内容,以便查询哪些计数器是以系统滴答数为单位的。如下所示:
在 Description字段末尾会列出计时器的单位(如上图所示)。
JMXMAPI的底层实现的JMX(参见第7章的相关内容),因此,可以很容的通过平台MBean服务器和标准远程JMX代理来访问远程服务器的MBean。正如第11章中介绍的,JRCMD只能对连接到本地服务器上的JVM,而且要求JRCMD和JVM的启动用户是同一人。相比之下,使用JMXMAPI就可以克服这些限制,实现远程访问。
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.management.Attribute;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
/**
* Simple code example on how to execute
* ctrl-break handlers remotely.
*
* Usage:
* RemoteJRCMD -host -port -user -pass -command []
*
* All arguments are optional. If no command is
* specified, all performance counters and their
* current values are listed.
*
* @author Marcus Hirt
*/
public final class RemoteJRCMD {
private final static String KEY_CREDENTIALS = "jmx.remote.credentials";
private final static String JROCKIT_PERFCOUNTER_MBEAN_NAME = "oracle.jrockit.management:type=PerfCounters";
private final static String JROCKIT_CONSOLE_MBEAN_NAME = "oracle.jrockit.management:type=JRockitConsole";
private final static String[] SIGNATURE = new String[] {"java.lang.String"};
private final static String DIAGNOSTIC_COMMAND_MBEAN_NAME = "oracle.jrockit.management:type=DiagnosticCommand";
public static void main(String[] args) throws Exception {
HashMap<String, String> commandMap = parseArguments(args);
executeCommand(
commandMap.get("-host"),
Integer.parseInt(commandMap.get("-port")),
commandMap.get("-user"),
commandMap.get("-password"),
commandMap.get("-command"));
}
private static HashMap<String, String> parseArguments(String[] args) {
HashMap<String, String> commandMap = new HashMap<String, String>();
commandMap.put("-host", "localhost");
commandMap.put("-port", "7091");
for (int i = 0; i < args.length; i++) {
if (args[i].startsWith("-")) {
StringBuilder buf = new StringBuilder();
int j = i + 1;
while (j < args.length && !args[j].startsWith("-")) {
buf.append(" ");
buf.append(args[j++]);
}
commandMap.put(args[i], buf.toString().trim());
i = j - 1;
}
}
return commandMap;
}
@SuppressWarnings("unchecked")
public static void executeCommand(String host, int port, String user, String password, String command) throws Exception {
MBeanServerConnection server = null;
JMXConnector jmxc = null;
Map<String, Object> map = null;
if (user != null || password != null) {
map = new HashMap<String, Object>();
final String[] credentials = new String[2];
credentials[0] = user;
credentials[1] = password;
map.put(KEY_CREDENTIALS, credentials);
}
// Use same convention as Sun. localhost:0 means
// "VM, monitor thyself!"
if (host.equals("localhost") && port == 0) {
server = ManagementFactory.getPlatformMBeanServer();
} else {
jmxc = JMXConnectorFactory.newJMXConnector(
createConnectionURL(host, port), map);
jmxc.connect();
server = jmxc.getMBeanServerConnection();
}
System.out.println("Connected to " + host+ ":" + port);
try {
server.getMBeanInfo(new ObjectName(JROCKIT_CONSOLE_MBEAN_NAME));
} catch (InstanceNotFoundException e1) {
server.createMBean("oracle.jrockit.management.JRockitConsole", null);
}
if (command == null) {
ObjectName perfCounterObjectName = new ObjectName(JROCKIT_PERFCOUNTER_MBEAN_NAME);
System.out.println("Listing all counters...");
MBeanAttributeInfo[] attributes = server.getMBeanInfo(perfCounterObjectName).getAttributes();
System.out.println("Counter\tValue\n=======\t====");
String[] attributeNames = new String[attributes.length];
for (int i = 0; i < attributes.length; i++) {
attributeNames[i] = attributes[i].getName();
}
Iterator valueIter = server.getAttributes(
perfCounterObjectName,
attributeNames).iterator();
while (valueIter.hasNext()) {
Attribute attr = (Attribute) valueIter.next();
System.out.println(attr.getName() + "\t=\t" + attr.getValue());
}
} else {
System.out.println("Invoking the ctrl-break command '" + command + "'...");
ObjectName consoleObjectName = new ObjectName(DIAGNOSTIC_COMMAND_MBEAN_NAME);
Object[] params = new Object[1];
params[0] = command;
System.out.println("The CtrlBreakCommand returned: \n" + server.invoke(consoleObjectName, "execute", params, SIGNATURE));
}
if (jmxc != null) {
jmxc.close();
}
}
private static JMXServiceURL createConnectionURL(String host, int port) throws MalformedURLException {
return new JMXServiceURL("rmi", "", 0, "/jndi/rmi://" + host + ":" + port + "/jmxrmi");
}
}
使用方式如下所示:
java RemoteJRCMD –command <command string> -host <host> -port <port>
其中:
start_flightrecording name=MyRecording duration=30s
;localhost
;下面的示例会列出所有性能计数器:
java RemoteJRCMD
下面的示例会列出主机bisty
,端口4711中JRockit JVM所支持的所有诊断命令:
java RemoteJRCMD -command help -host bitsy -port 4711
下面的示例会在目标JVM中开启一个为期30秒的记录任务,并记录结束后将记录内容写入到指定文件中:
java RemoteJRCMD -command start_flightrecording name=myrecording filename=c:\tmp\myrecording.jfr
duration=30s